Skip to main content

04 - 训练框架怎么接环境

前置03 - 环境接口标准。本篇讨论的是接口确定之后,工程上谁来管环境的生命周期。

本篇回答:训练框架、沙箱平台、集群编排三者之间,环境这件事该由谁负责?不同框架的选择差在哪,代价各是什么?

本篇会用到的词

意思
rollout 阶段一轮训练里「让模型去环境里试」的那一段。这段时间 GPU 主要在做推理,训练器空着
更新阶段拿采到的轨迹算梯度、更新参数的那一段。这段时间环境空着
colocate(同置)训练和推理共用同一批 GPU,交替使用。省卡,但两个阶段没法重叠
disaggregate(分离)训练和推理各占一批 GPU。可以流水线重叠,代价是卡更多
Ray分布式执行框架,常被 RL 框架用来管理异构角色(训练器、推理引擎、环境)之间的资源分配
长程(long-horizon)一条轨迹要走很多步、持续很久的任务。编码 Agent 是典型,一条可能几十步、几分钟
GPU 利用率这里特指 GPU 真在算的时间占比。环境慢会直接体现为这个数字掉下去

一、协议定好了,还是有一件事没人管

03 篇讲的是训练框架和环境之间「用什么话对话」。假设这件事已经解决了,你的代码现在可以对一个环境说「执行这个动作」并拿到回复。

然后你要开一万个这样的环境。

于是问题变成:谁去把这一万台机器创建出来?谁在轮次结束后把它们销毁?中间有三百台卡死了,谁发现、谁重来? 这些事协议一个字都没提,但少了任何一件,训练都跑不起来。

代价具体落在哪,看一轮训练的时间轴就清楚了:

同一轮训练,环境快与环境慢的时间轴对比环境快环境起停GPU 推理:生成动作环境执行GPU 更新参数GPU 真在算的时间占比高 —— 环境只占开头一小段和中间一小段环境慢环境起停:拉镜像 · 装依赖 · 初始化GPU 推理环境执行 + 等待GPU 更新同样一轮,深色的等待段吃掉了大半时间 —— 几千张卡就在这段里空转这就是 01 篇那句话的量化版本:环境不吃 GPU,但它决定了吃 GPU 的那两段有没有活干。而且这个损失会被并发数放大 —— 一轮要跑几万条 rollout,任何一条卡住都可能让整批等在那里。
真实系统会用异步与流水线把这两条时间轴部分重叠,但重叠的前提是环境侧能稳定按需供给。环境起停不可预测时,调度器无从流水线化。

二、「谁把环境拉起来」的三种答案

同一件事,三个地方可以承担① 训练框架进程内自管环境就是一个 Python 对象或一个本地子进程代表:skyrl-gym数学 · 代码 · 检索 · SQL 类任务② 交给专门的沙箱平台训练框架只发 HTTP 请求起停 · 快照 · 回收都在平台侧代表:AgentENV · E2B · Daytona需要完整机器的任务③ 交给通用集群编排每条 rollout 一个 K8s Job复用已有的集群能力代表:agent-lightning不想再引入一套基础设施① 最简单,但只适合「环境等于一段代码」的任务。一旦任务需要真实文件系统和进程,它就撑不住了。② 能力最强,代价是多一套要运维的系统 —— 只有当环境规模真的上来了才划算。③ 复用 K8s 的调度与配额,但 Pod 的起停是秒级的,做不到 02 篇那种 50 毫秒级恢复,也没有 fork 语义。
选哪一种,本质上是在回答「环境到底是不是一台机器」。是的话只有 ② 和 ③ 可选,而 ② 与 ③ 之间的分界是你能不能接受秒级起停。

三、六个框架各自把这件事交给了谁

同一个问题,六家给了六个不同的答案。看「它把环境当成什么」这一列,比看 star 数有用得多:

框架协议建仓它把环境当成什么
verl-project/verl23,040Apache-2.02024-10-31当成自己的一部分 —— 多轮工具调用和 agent 循环直接写在框架里,不往外拆
microsoft/agent-lightning17,525MIT2025-06-18根本不定义环境是什么。它在模型 API 那一层横插一刀,你的 agent 代码一行不改;真要开机器的时候,交给 K8s 起一个 Job
OpenPipe/ART10,603Apache-2.02025-03-10当成你已经有的那个 agent —— 它的目标是给线上跑着的 agent 做在岗训练,环境就是它本来的运行环境
alibaba/ROLL3,365Apache-2.02025-05-28当成一类要抢资源的角色,和训练器、推理引擎平级,统一交给 Ray 去分配
NovaSky-AI/SkyRL2,176Apache-2.02025-04-22当成一个独立的包,单独维护、单独演进(见下面 3.1)
PrimeIntellect-ai/prime-rl1,952Apache-2.02025-02-18当成一份可以下载的任务包 —— 环境和任务是同一样东西,从 Environments Hub 上拉

3.1 SkyRL 的分层值得单独看

它把三件事拆成了三个包,这个切分本身就是对本篇问题的一个明确回答:

管什么
skyrl-train训练框架,只管梯度和参数
skyrl-gym工具使用类任务的环境库,用 Gymnasium 接口实现数学、代码、检索、SQL 等环境
skyrl-agent长程、真实环境任务的 agent 层,专门处理多轮工具使用

为什么要有第三层skyrl-gym 那种 Gymnasium 接口对「一步就是一次工具调用」的任务够用,但编码 Agent 那类任务一条轨迹几十步、跑几分钟,需要单独的调度与容错逻辑 —— 这正是 03 篇里 step 抽象撑不住的地方,SkyRL 的做法是再加一层而不是改接口。

3.2 verl 与 ROLL:把资源分配当作一等问题

这两个框架都不太关心「环境接口长什么样」,它们关心的是另一件事:这几种东西该怎么抢机器。

回到第一节那张时序图。训练器要 GPU 算梯度,推理引擎要 GPU 出 token,环境要的是 CPU 和磁盘 IO —— 三者要的硬件不一样,忙的时间段也不一样。如果一开始就把机器切死(这几台给训练、这几台给推理、这几台跑环境),那么无论哪个阶段,总有一批机器闲着。

ROLL 的说法最直白:用 Ray 做多角色分布式,让资源能按当下谁在忙来分。

四、一个容易被忽略的现实:数据得对得上

接环境时最常见的翻车不在性能,在训练数据和真实运行不一致

具体表现是:训练时用的是一个为了好接入而简化过的 harness,上线时用的是真实的那个。两者的提示词模板、工具描述、错误处理都有细微差别,于是训练出来的行为在生产上不复现。

03 篇里 verifiers 和 agent-lightning 都在回应这件事,只是方向不同:

  • verifiers:把真实 harness(Claude Code、Codex、mini-swe-agent)直接当作接口单位
  • agent-lightning:在模型 API 层拦截,agent 代码零改动,工具、上下文、控制流、环境全部保持原样

判断一个方案有没有认真处理这个问题,看一个问题就够了:训练时跑的 harness,和你上线要用的那个,是不是同一份代码。

五、落地顺序建议

如果你现在要从零搭一套,建议按这个顺序,而不是一上来就选最强的:

① 先用最笨的方式跑通一条 rollout。 本地 Docker、串行执行、几十条样本。目标是确认任务能训得动、奖励函数没写反 —— 这一步失败率比想象中高得多。

② 把并发提到几百条,看瓶颈在哪。 大概率会撞在环境起停上。这时候再决定要不要引入 ② 或 ③ 那种方案。

③ 只有当环境成为确定的瓶颈时,才上专门的环境平台。 02 篇那套东西解决的是几万到几十万并发的问题,几百并发时它带来的运维成本大于收益。

④ 从第一天起就把 harness 对齐。 这一条和规模无关,越晚做代价越大 —— 训练数据是按旧 harness 采的,换了 harness 就得重采。

下一篇05 - 任务环境与选型:环境跑起来之后,用什么任务去训?SWE-bench 系、OS 与浏览器系、工具使用系各自的定位与陷阱。

← 回到 专题索引  ·  Agent Infra 板块总览